package ${packageName}.mvp.model.api;

import android.annotation.SuppressLint;
import android.util.Log;
import android.view.Gravity;

import com.dovar.dtoast.DToast;
import com.jpxx.base.http.exception.HttpProxyException;
import com.jpxx.base.http.response.APIError;
import com.jpxx.base.http.response.APIResponse;
import com.jpxx.lib.klog.KLog;
import com.jpxx.base.http.error.GlobalErrorTransformer;
import com.jpxx.base.http.error.func.Suppiler;
import com.jpxx.base.http.error.retry.RetryConfig;
import com.jpxx.base.util.MainLooper;
import com.jpxx.base.util.ToastHelper;

import java.net.ConnectException;
import java.net.SocketTimeoutException;

import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import retrofit2.HttpException;

/**
 * APP全局异常拦截及重试管理器
 */

public class GlobalErrorProcessor {
    /**
     * @param noticeErrorInfo true, 弹出错误提醒; false, 不弹
     * @param <T>             数据包装类型名，必须是BaseResponseMessage的子类
     * @return
     */
    public static <T extends APIResponse> GlobalErrorTransformer<T> processGlobalError(boolean noticeErrorInfo) {
        //onNextInterceptor
        Function<T, Observable<T>> onNextInterceptor =
                new Function<T, Observable<T>>() {
                    @Override
                    public Observable<T> apply(T it) throws Exception {
                        if(it.isOK()){
                            return Observable.just(it);
                        } else{
                            return Observable.error(new APIError.ServerError(it.getErrorCode(), it.getErrorMsg()));
                        }
                    }
                };

        //onErrorResumeNext
        Function<Throwable, Observable<T>> onErrorResumeNext =
                new Function<Throwable, Observable<T>>() {
                    @Override
                    public Observable<T> apply(Throwable error) throws Exception {
                        if (error instanceof HttpException) {
                            HttpException httpException = (HttpException) error;
                            return Observable.error(new APIError.ServerError(String.valueOf(httpException.code()), httpException.response().errorBody().string()));
                        } else if (error instanceof ConnectException
                                || error instanceof SocketTimeoutException) {
                            return Observable.error(new APIError.ConnectFailedException(error));
                        } else {
                            return Observable.error(error);
                        }
                    }
                };

        //onErrorRetrySupplier
        Function<Throwable, RetryConfig> onErrorRetrySupplier =
                new Function<Throwable, RetryConfig>() {
                    @Override
                    public RetryConfig apply(Throwable error) throws Exception {
                        if (error instanceof APIError.ServerError) {
                            return new RetryConfig();   //server error 不重试
                        } else if (error instanceof APIError.ConnectFailedException) {
                            // 默认重试1次
                            return new RetryConfig(new Suppiler<Single<Boolean>>() {
                                @Override
                                public Single<Boolean> call() {
                                    return Single.just(true);
                                }
                            });
                        } else if(error instanceof HttpProxyException){
                            return new RetryConfig();   //不重试
                        } else {
                            return new RetryConfig();   //其他异常都不重试
                        }
                    }
                };

        //onErrorConsumer
        Consumer<Throwable> onErrorConsumer = new Consumer<Throwable>() {
            @SuppressLint("CheckResult")
            @Override
            public void accept(Throwable error) throws Exception {
                if (error instanceof APIError.ServerError) {
                    APIError.ServerError serverError = (APIError.ServerError) error;
                    if (noticeErrorInfo) {
                        MainLooper.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                ToastHelper.toastMessage(serverError.errorMsg, Gravity.CENTER, DToast.DURATION_SHORT);
                            }
                        });
                    }
                } else {
                    KLog.w("rx stream Exception", "其它异常: " + Log.getStackTraceString(error));
                }
            }
        };

        return new GlobalErrorTransformer<T>(
                onNextInterceptor,
                onErrorResumeNext,
                onErrorRetrySupplier,
                onErrorConsumer
        );
    }
}
